home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / fontutil.6 / fontutil / fontutils-0.6 / bzr / bzr_output.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-18  |  10.9 KB  |  393 lines

  1. /* bzr_output.c: write a BZR-format font file.
  2.  
  3. Copyright (C) 1992 Free Software Foundation, Inc.
  4.  
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.
  9.  
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include "bzr.h"
  22. #include "file-output.h"
  23. #include "scaled-num.h"
  24. #include "spline.h"
  25.  
  26. #include "bzr_opcodes.h"
  27. #include "bzr_types.h"
  28.  
  29. /* Where the output will go.  */
  30. static FILE *bzr_output_file = NULL;
  31. static string bzr_output_filename;
  32.  
  33.  
  34. /* We remember the design size, so we can scale by it.  */
  35. static real design_size = 0.0;
  36.  
  37.  
  38. /* We keep track of the character locator information as we output
  39.    characters, to save the caller from doing the bookkeeping.  */
  40. static char_locator_type char_loc[MAX_CHARCODE + 1];
  41.  
  42.  
  43. /* The bounding box of all the characters we have written.  The values
  44.    here should be the largest and smallest possible numbers.  */
  45. static real_bounding_box_type font_bb
  46.   = { FLT_MAX, FLT_MIN, FLT_MAX, FLT_MIN };
  47.  
  48.  
  49. /* Low-level output.  These macros call the corresponding lib routines
  50.    with the static variables for the input file and filename.  */
  51.  
  52. #define BZR_FTELL() xftell (bzr_output_file, bzr_output_filename)
  53. #define BZR_PUT_BYTE(b) put_byte (b, bzr_output_file, bzr_output_filename)
  54. #define BZR_PUT_TWO(n) put_two (n, bzr_output_file, bzr_output_filename)
  55. #define BZR_PUT_FOUR(n) put_four (n, bzr_output_file, bzr_output_filename)
  56. #define BZR_PUT_N_BYTES(n, a) \
  57.   put_n_bytes (n, a, bzr_output_file, bzr_output_filename);
  58.  
  59.  
  60. /* Determine whether the number N (in points) can be part of an abbrev
  61.    command, i.e., its magnitude is less than half the design size.  */
  62. #define MIN_ABBREV (-32768.0 / 65535.0)
  63. #define MAX_ABBREV  (32767.0 / 65535.0)
  64. #define ABBREV_P(n) (MIN_ABBREV < (n) / design_size            \
  65.                      && (n) / design_size < MAX_ABBREV)
  66.  
  67. static void bzr_put_scaled (real);
  68. static void bzr_put_design_scaled (real);
  69. static void bzr_put_point (real_coordinate_type);
  70. static void bzr_put_abbrev_scaled (real);
  71. static void bzr_put_abbrev_design_scaled (real);
  72. static void bzr_put_abbrev_point (real_coordinate_type);
  73.  
  74. /* Routines to start and end writing a file.  (For the user to call.) 
  75.    We make sure the caller doesn't try to have two output files open
  76.    simultaneously. */
  77.  
  78. boolean
  79. bzr_open_output_file (string filename)
  80. {
  81.   assert (bzr_output_file == NULL);
  82.  
  83.   bzr_output_filename = filename;
  84.   bzr_output_file = fopen (filename, "w");
  85.  
  86.   if (bzr_output_file != NULL)
  87.     {
  88.       unsigned this_char;
  89.  
  90.       for (this_char = 0; this_char <= MAX_CHARCODE; this_char++)
  91.         CHAR_POINTER (char_loc[this_char]) = NULL_BYTE_PTR;
  92.       return true;
  93.     }
  94.   else
  95.     return false;
  96. }
  97.  
  98.  
  99. void
  100. bzr_close_output_file ()
  101. {
  102.   assert (bzr_output_file != NULL);
  103.  
  104.   xfclose (bzr_output_file, bzr_output_filename);
  105.   bzr_output_filename = NULL;
  106.   bzr_output_file = NULL;
  107. }
  108.  
  109. /* The preamble.  Since we are supposed to scale many numbers in the BZR
  110.    file by the design size, we squirrel that value away.  */
  111.  
  112. void
  113. bzr_put_preamble (bzr_preamble_type p)
  114. {
  115.   unsigned comment_length;
  116.  
  117.   assert (bzr_output_file != NULL);
  118.  
  119.   bzr_put_scaled (BZR_DESIGN_SIZE (p));
  120.   design_size = BZR_DESIGN_SIZE (p);
  121.  
  122.   comment_length = strlen (BZR_COMMENT (p));
  123.   if (comment_length > 255)
  124.     {
  125.       string comment = xmalloc (256);
  126.  
  127.       WARNING2 ("BZR comment `%s' too long (%u characters, which is > 255)",
  128.                 BZR_COMMENT (p), comment_length);
  129.       /* We can't just put a null into BZR_COMMENT, since it might be in
  130.          read-only storage.  */
  131.       comment_length = 255;
  132.       strncpy (comment, BZR_COMMENT (p), comment_length);
  133.       comment[comment_length] = 0;
  134.       BZR_COMMENT (p) = comment;
  135.     }
  136.  
  137.   BZR_PUT_BYTE (comment_length);
  138.   BZR_PUT_N_BYTES (comment_length, BZR_COMMENT (p));
  139. }
  140.  
  141. /* Characters.  */
  142.  
  143. /* Write the character C to `bzr_output_file' (which must already be
  144.    open).  It is a (non-fatal) error to try to write two characters with
  145.    the same character code.  */
  146.  
  147. void
  148. bzr_put_char (bzr_char_type c)
  149. {
  150.   unsigned this_list;
  151.   void (*put_design_scaled) (real);
  152.   void (*put_point) (real_coordinate_type);
  153.   spline_list_array_type shape = BZR_SHAPE (c);
  154.   char_locator_type *this_char_loc = &(char_loc[CHARCODE (c)]);
  155.  
  156.   assert (bzr_output_file != NULL);
  157.  
  158.   /* We should update the character locator information first, to be
  159.      sure we don't try to output the same character twice.  */
  160.   if (CHAR_POINTER (*this_char_loc) != NULL_BYTE_PTR)
  161.     {
  162.       WARNING1 ("Attempt to output BZR character %u more than once; only \
  163. the first will be written", CHARCODE (c));
  164.       return;
  165.     }
  166.  
  167.   /* OK, this is a new character.  Remember our current position, for
  168.      writing the postamble.  */
  169.   CHAR_POINTER (*this_char_loc) = BZR_FTELL ();
  170.  
  171.   /* Now, on to the real business of outputting the character
  172.      definition.  If all numbers are small enough, we can use the
  173.      abbreviated boc.  */
  174.   put_design_scaled
  175.     = (ABBREV_P (CHAR_SET_WIDTH (c))
  176.        && ABBREV_P (CHAR_MIN_COL (c)) && ABBREV_P (CHAR_MIN_ROW (c))
  177.        && ABBREV_P (CHAR_MAX_COL (c)) && ABBREV_P (CHAR_MAX_ROW (c)))
  178.       ? bzr_put_abbrev_design_scaled : bzr_put_design_scaled;
  179.   BZR_PUT_BYTE (put_design_scaled == bzr_put_abbrev_design_scaled
  180.                 ? BOC_ABBREV : BOC);
  181.   BZR_PUT_BYTE (CHARCODE (c));
  182.   put_design_scaled (CHAR_SET_WIDTH (c));
  183.   
  184.   /* We believe the bounding box we are given, since to compute it
  185.      ourselves would require rasterizing the splines, which should not
  186.      be part of this routine.  */
  187.   put_design_scaled (CHAR_MIN_COL (c));
  188.   put_design_scaled (CHAR_MIN_ROW (c));
  189.   put_design_scaled (CHAR_MAX_COL (c));
  190.   put_design_scaled (CHAR_MAX_ROW (c));
  191.  
  192.   /* Update the font bounding box.  */
  193.   if (CHAR_MIN_COL (c) < MIN_COL (font_bb))
  194.     MIN_COL (font_bb) = CHAR_MIN_COL (c);
  195.   if (CHAR_MAX_COL (c) > MAX_COL (font_bb))
  196.     MAX_COL (font_bb) = CHAR_MAX_COL (c);
  197.   if (CHAR_MIN_ROW (c) < MIN_ROW (font_bb))
  198.     MIN_ROW (font_bb) = CHAR_MIN_ROW (c);
  199.   if (CHAR_MAX_ROW (c) > MAX_ROW (font_bb))
  200.     MAX_ROW (font_bb) = CHAR_MAX_ROW (c);
  201.  
  202.   for (this_list = 0; this_list < SPLINE_LIST_ARRAY_LENGTH (shape);
  203.        this_list++)
  204.     {
  205.       unsigned this_spline;
  206.       spline_list_type list = SPLINE_LIST_ARRAY_ELT (shape, this_list);
  207.       spline_type first_spline = SPLINE_LIST_ELT (list, 0);
  208.  
  209.       BZR_PUT_BYTE (START_PATH);
  210.       bzr_put_point (START_POINT (first_spline));
  211.  
  212.       for (this_spline = 0; this_spline < SPLINE_LIST_LENGTH (list);
  213.            this_spline++)
  214.         {
  215.           spline_type s = SPLINE_LIST_ELT (list, this_spline);
  216.  
  217.           if (SPLINE_DEGREE (s) == LINEAR)
  218.             {
  219.               one_byte opcode;
  220.               if (ABBREV_P (END_POINT (s).x) && ABBREV_P (END_POINT (s).y))
  221.                 {
  222.                   put_point = bzr_put_abbrev_point;
  223.                   opcode = LINE_ABBREV;
  224.                 }
  225.               else
  226.                 {
  227.                   put_point = bzr_put_point;
  228.                   opcode = LINE;
  229.                 }
  230.               
  231.               BZR_PUT_BYTE (opcode);
  232.               put_point (END_POINT (s));
  233.             }
  234.  
  235.           else if (SPLINE_DEGREE (s) == CUBIC)
  236.             {
  237.               one_byte opcode;
  238.               
  239.               if (ABBREV_P (CONTROL1 (s).x) && ABBREV_P (CONTROL1 (s).y)
  240.                   && ABBREV_P (CONTROL2 (s).x) && ABBREV_P (CONTROL2 (s).y)
  241.                   && ABBREV_P (END_POINT (s).x) && ABBREV_P (END_POINT (s).y))
  242.                 {
  243.                   put_point = bzr_put_abbrev_point;
  244.                   opcode = SPLINE_ABBREV;
  245.                 }
  246.               else
  247.                 {
  248.                   put_point = bzr_put_point;
  249.                   opcode = SPLINE;
  250.                 }
  251.                 
  252.               BZR_PUT_BYTE (opcode);
  253.               put_point (CONTROL1 (s));
  254.               put_point (CONTROL2 (s));
  255.               put_point (END_POINT (s));
  256.             }
  257.  
  258.           else
  259.             FATAL2 ("bzr_put_char: Spline #%d's degree was %d in out_splines", 
  260.                     this_spline, SPLINE_DEGREE (s));
  261.         }
  262.     }
  263.  
  264.   BZR_PUT_BYTE (EOC);
  265. }
  266.  
  267. /* The postamble.  */
  268.  
  269. void
  270. bzr_put_postamble ()
  271. {
  272.   unsigned c;
  273.   byte_count_type post_ptr;
  274.   unsigned nchars = 0;
  275.   
  276.   assert (bzr_output_file != NULL);
  277.  
  278.   post_ptr = BZR_FTELL ();
  279.   BZR_PUT_BYTE (POST);
  280.  
  281.   /* First comes the font bounding box.  */
  282.   bzr_put_design_scaled (MIN_COL (font_bb));
  283.   bzr_put_design_scaled (MIN_ROW (font_bb));
  284.   bzr_put_design_scaled (MAX_COL (font_bb));
  285.   bzr_put_design_scaled (MAX_ROW (font_bb));
  286.  
  287.   /* Then the character locators.  */
  288.   for (c = 0; c <= MAX_CHARCODE; c++)
  289.     {
  290.       char_locator_type this_char_loc = char_loc[c];
  291.  
  292.       if (CHAR_POINTER (this_char_loc) != NULL_BYTE_PTR)
  293.         {
  294.           if (CHAR_POINTER (this_char_loc) < (1 << 16))
  295.             {
  296.               BZR_PUT_BYTE (CHAR_LOC_ABBREV);
  297.               BZR_PUT_BYTE (c);
  298.               BZR_PUT_TWO (CHAR_POINTER (this_char_loc));
  299.             }
  300.           else
  301.             {
  302.               BZR_PUT_BYTE (CHAR_LOC);
  303.               BZR_PUT_BYTE (c);
  304.               BZR_PUT_FOUR (CHAR_POINTER (this_char_loc));
  305.             }
  306.          nchars++;
  307.         }
  308.     }
  309.  
  310.   /* Then the number of characters.  */
  311.   BZR_PUT_BYTE (nchars);
  312.   
  313.   /* Now a pointer back to the postamble.  */
  314.   BZR_PUT_BYTE (POST_POST);
  315.   BZR_PUT_FOUR (post_ptr);
  316.   BZR_PUT_BYTE (BZR_ID);
  317.   BZR_PUT_BYTE (NO_OP);
  318. }
  319.  
  320. /* Low-level output routines.  */
  321.  
  322. static void
  323. bzr_put_scaled (real r)
  324. {
  325.   scaled s;
  326.  
  327.   if (r >= 256.0)
  328.     {
  329.       WARNING1 ("bzr_put_scaled: Value too large to be output (%f)", r);
  330.       r = 255.999;
  331.     }
  332.  
  333.   s = real_to_scaled (r);
  334.  
  335.   BZR_PUT_BYTE ((s & 0xff0000) >> 16);
  336.   BZR_PUT_BYTE ((s & 0xff00) >> 8);
  337.   BZR_PUT_BYTE ((s & 0xff));
  338. }
  339.  
  340.  
  341. /* We have remembered the design size value from when we output the
  342.    preamble.  */
  343.  
  344. static void
  345. bzr_put_design_scaled (real r)
  346. {
  347.   bzr_put_scaled (r / design_size);
  348. }
  349.  
  350.  
  351. static void
  352. bzr_put_point (real_coordinate_type c)
  353. {
  354.   bzr_put_design_scaled (c.x);
  355.   bzr_put_design_scaled (c.y);
  356. }
  357.  
  358.  
  359. static void
  360. bzr_put_abbrev_scaled (real r)
  361. {
  362.   scaled s;
  363.  
  364.   if (r > MAX_ABBREV || r <= MIN_ABBREV)
  365.     {
  366.       WARNING1 ("bzr_put_abbrev_scaled: Value too large to be output (%f)", r);
  367.       r = MAX_ABBREV;
  368.     }
  369.  
  370.   s = real_to_scaled (r);
  371.  
  372.   BZR_PUT_BYTE ((s & 0xff00) >> 8);
  373.   BZR_PUT_BYTE ((s & 0xff));
  374. }
  375.  
  376.  
  377. /* We have remembered the design size value from when we output the
  378.    preamble.  */
  379.  
  380. static void
  381. bzr_put_abbrev_design_scaled (real r)
  382. {
  383.   bzr_put_abbrev_scaled (r / design_size);
  384. }
  385.  
  386.  
  387. static void
  388. bzr_put_abbrev_point (real_coordinate_type c)
  389. {
  390.   bzr_put_abbrev_design_scaled (c.x);
  391.   bzr_put_abbrev_design_scaled (c.y);
  392. }
  393.